package org.example.mq.common.network.mqclient;

import org.example.mq.common.BinaryTool;
import org.example.mq.common.MqException;
import org.example.mq.common.Request;
import org.example.mq.common.Response;
import org.example.mq.common.network.mqservice.BasicReturns;
import org.example.mq.common.network.mqservice.SubScribeReturns;

import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Connection {

    private Socket socket = null;

    private ConcurrentHashMap<String,Channel> channelMap = new ConcurrentHashMap<>();

    private InputStream inputStream;
    private OutputStream outputStream;
    private DataOutputStream dataOutputStream;
    private DataInputStream dataInputStream;

    private ExecutorService callbackPool  = null;

    public Connection(String host, int port) throws IOException {
        socket = new Socket(host, port);
        inputStream = socket.getInputStream();
        outputStream = socket.getOutputStream();
        dataInputStream = new DataInputStream(inputStream);
        dataOutputStream = new DataOutputStream(outputStream);

        callbackPool = Executors.newFixedThreadPool(4);

        //扫描线程
        Thread thread = new Thread(()->{
            try{
                while (!socket.isClosed()){
                    //如果不为空，就一直读取内容
                    Response response = readResponse();
                    //对读取的响应内容，进行处理（有两种情况）
                    dispatchResponse(response);
                }
            } catch (SocketException e){
                System.out.println("连接正常断开");
            } catch (IOException | ClassNotFoundException | MqException e) {
                System.out.println("连接异常断开");
                e.printStackTrace();
            }
        });
        thread.start();
    }


    /*
    *
    * */
    public void close() throws IOException {
        callbackPool.shutdownNow();
        channelMap = null;
        inputStream.close();
        outputStream.close();
        socket.close();
    }



    /*
    * 处理服务器返回的响应（1.客户端发送请求，服务器返回的响应 2.服务器直接返回的内容（回调函数））
    * */
    private void dispatchResponse(Response response) throws IOException, ClassNotFoundException, MqException {
        //回调函数的情况
        if(response.getType()==0xc){
            //将其中的2进制内容转换为对象
            SubScribeReturns subScribeReturns = (SubScribeReturns) BinaryTool.fromBytes(response.getPayload());
            //根据其中的ChannelId找到Channel
            Channel channel = channelMap.get(subScribeReturns.getChannelId());
            if(channel==null){
                throw new MqException("该消息对应的Channel在客户端不存在");
            }
            //在扫描线程中，执行回调函数并不合适，所有专门创建一个线程池来执行
//            channel.getConsumer().handleDelivery();
            callbackPool.submit(()->{
                try {
                    channel.getConsumer().handleDelivery(subScribeReturns.getConsumerTag(), subScribeReturns.getBasicProperties(),
                            subScribeReturns.getBody());
                } catch (MqException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }else {
            BasicReturns basicReturns = (BasicReturns) BinaryTool.fromBytes(response.getPayload());
            //将接收到的响应，放在哈希表中存储
            //先判断有没有重复
            Channel channel = channelMap.get(basicReturns.getChannelId());
            if(channel==null){
                throw new MqException("该消息对应的Channel在客户端不存在");
            }
            channel.putReturns(basicReturns);
        }
    }

    /*
    * 发送请求
    * */
    public void writeRequest(Request request) throws IOException {
        dataOutputStream.writeInt(request.getType());
        dataOutputStream.writeInt(request.getLength());
        dataOutputStream.write(request.getPayload());
        dataOutputStream.flush();
        System.out.println("发送请求成功");
    }

    /*
    * 获取响应
    * */
    public Response readResponse() throws IOException {
        Response response = new Response();
        response.setType(dataInputStream.readInt());
        response.setLength(dataInputStream.readInt());
        byte[] payload = new byte[response.getLength()];
        int n = dataInputStream.read(payload);
        if(n != response.getLength()){
            throw new IOException("读取的响应数据不完整");
        }
        response.setPayload(payload);
        System.out.println("获取响应成功");
        return response;
    }

    /*
    * 创建channel
    * */
    public Channel createChannel() throws IOException {
        String channelId = "C-"+ UUID.randomUUID();
        Channel channel = new Channel(channelId,this);
        //放入这个哈希表中统计
        channelMap.put(channelId,channel);
        //也需要告知服务器，创建了channel
        boolean ok = channel.createChannel();
        if(!ok){
            //类似于事务的回滚
            channelMap.remove(channelId);
            return null;
        }
        return channel;
    }
}
